package com.ssyt.yt1.common.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ssyt.yt1.common.Constant;

/**
 * 数据库操作工具类
 *
 * @author Hsu.
 * @since 2015年12月28日
 */
public class DBUtil {

	private DBUtil() {

	}

	/**
	 * 得到数据库连接
	 * 
	 * @return
	 */
	public static Connection getConnection() {
		Connection connection = null;
		// 1、加载驱动
		try {
			Class.forName(Constant.DRIVER);

			// 2、连接数据库
			connection = DriverManager.getConnection(Constant.URL,
					Constant.USER, Constant.PASSWORD);
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("驱动加载失败！");
		} catch (SQLException e) {
			throw new RuntimeException("数据库连接失败");
		}
		return connection;
	}

	/**
	 * 关闭ResultSet
	 * 
	 * @param preparedStatement
	 */
	public static void close(ResultSet resultSet) {
		try {
			if (resultSet != null) {
				resultSet.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException("数据库资源释放失败");
		}
	}

	/**
	 * 关闭PreparedStatement
	 * 
	 * @param preparedStatement
	 */
	public static void close(PreparedStatement preparedStatement) {
		try {
			if (preparedStatement != null) {
				preparedStatement.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException("数据库资源释放失败");
		}
	}

	/**
	 * 关闭Connection
	 * 
	 * @param preparedStatement
	 */
	public static void close(Connection connection) {
		try {
			if (connection != null) {
				connection.close();
			}
		} catch (SQLException e) {
			throw new RuntimeException("数据库资源释放失败");
		}
	}

	/**
	 * 增、删、改的数据库资源释放
	 * 
	 * @param connection
	 * @param preparedStatement
	 */
	public static void close(Connection connection,
			PreparedStatement preparedStatement) {
		close(preparedStatement);
		close(connection);
	}

	/**
	 * 增、删、改、查的数据库资源释放
	 * 
	 * @param connection
	 * @param preparedStatement
	 */
	public static void close(Connection connection,
			PreparedStatement preparedStatement, ResultSet resultSet) {
		close(resultSet);
		close(preparedStatement);
		close(connection);
	}

	/**
	 * 数据更新操作<br>
	 * 注：此方法仅用于单个更新操作，如果有事务的情况还得手动控制Connection并开启事务操作！
	 * 
	 * @param sql
	 *            传入预编译的sql语句
	 * @param paramList
	 *            向模版中?赋值的参数
	 * @return 受影响的行数
	 * @throws RuntimeException
	 *             如果更新失败会返回此异常
	 */
	public static int executeUpdate(String sql, List<Object> paramList) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		try {
			connection = DBUtil.getConnection();
			preparedStatement = connection.prepareStatement(sql);
			setParameter(paramList, preparedStatement);
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException("数据更新失败");
		} finally {
			DBUtil.close(connection, preparedStatement);
		}
	}

	/**
	 * 
	 * 数据更新操作<br>
	 * 注：此方法仅用于单个更新操作，如果有事务的情况还得手动控制Connection并开启事务操作！
	 * 
	 * @param sql
	 *            传入预编译的sql语句
	 * @param params
	 *            向模版中?赋值的参数
	 * @return 受影响的行数
	 * @throws RuntimeException
	 *             如果更新失败会返回此异常
	 */
	public static int executeUpdate(String sql, Object... params) {
		return executeUpdate(sql, Arrays.asList(params));
	}

	/**
	 * 查询操作<br>
	 * 注：此方法只能做select * from xx的简单（数据量小）操作，如果用来查询数据量比较大的表性能会很低！
	 * 
	 * @param sql
	 *            传入预编译的sql语句
	 * @param paramList
	 *            向模版中?赋值的参数
	 * @return 数据里面的所有信息
	 * @throws RuntimeException
	 *             如果查询会返回此异常
	 */
	public static List<Map<String, Object>> executeQuery(String sql,
			List<Object> paramList) {
		List<Map<String, Object>> resultList = new ArrayList<>();
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		try {
			connection = DBUtil.getConnection();
			preparedStatement = connection.prepareStatement(sql);
			setParameter(paramList, preparedStatement);
			resultSet = preparedStatement.executeQuery();
			// 读取取数据库结构
			ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
			// 得到有多少列
			int columns = resultSetMetaData.getColumnCount();
			while (resultSet.next()) {
				Map<String, Object> dataMap = new HashMap<>();
				for (int i = 1; i <= columns; i++) {
					String columnName = resultSetMetaData.getColumnName(i);
					// key：数据库的字段名； value：字段所对应的值
					dataMap.put(columnName, resultSet.getObject(columnName));
				}
				resultList.add(dataMap);
			}
			return resultList;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException("数据查询失败");
		} finally {
			DBUtil.close(connection, preparedStatement, resultSet);
		}
	}

	/**
	 * 
	 * 查询操作 <br>
	 * 注：此方法只能做select * from xx的简单（数据量小）操作，如果用来查询数据量比较大的表性能会很低！
	 * 
	 * @param sql
	 *            传入预编译的sql语句
	 * @param paramList
	 *            向模版中?赋值的参数
	 * @return 数据里面的所有信息
	 * @throws RuntimeException
	 *             如果查询会返回此异常
	 */
	public static List<Map<String, Object>> executeQuery(String sql,
			Object... params) {
		return executeQuery(sql, Arrays.asList(params));
	}

	/**
	 * 参数设置
	 * 
	 * @param paramList
	 * @param preparedStatement
	 * @throws SQLException
	 */
	private static void setParameter(List<Object> paramList,
			PreparedStatement preparedStatement) throws SQLException {
		if (paramList != null) {
			for (int i = 0; i < paramList.size(); i++) {
				preparedStatement.setObject(i + 1, paramList.get(i));
			}
		}
	}
}
